*! version 2.9.0 28mar2017

* Possible improvements: allow in, if, reverse sort (like gsort)
* This uses Andrew Maurer's trick to clear the sort order:
* http://www.statalist.org/forums/forum/general-stata-discussion/mata/172131-big-data-recalling-previous-sort-orders


program define fsort
	syntax varlist, [Verbose]

	loc sortvar : sortedby

	if ("`sortvar'" == "`varlist'") {
		exit
	}
	else if ("`sortvar'" != "") {
		* Andrew Maurer's trick to clear `: sortedby'
		loc sortvar : word 1 of `sortvar'
		loc sortvar_type : type `sortvar'
		loc sortvar_is_str = strpos("`sortvar_type'", "str") == 1
		loc val = `sortvar'[1]

		if (`sortvar_is_str') {
			qui replace `sortvar' = cond(mi(`"`val'"'), ".", "") in 1
			qui replace `sortvar' = `"`val'"' in 1
		}
		else {
			qui replace `sortvar' = cond(mi(`val'), 0, .) in 1
			qui replace `sortvar' = `val' in 1
		}
		assert "`: sortedby'" == ""
	}

	fsort_inner `varlist', `verbose'
	sort `varlist' // dataset already sorted by `varlist' but flag `: sortedby' not set
end


program define fsort_inner, sortpreserve
	syntax varlist, [Verbose]
	loc verbose = ("`verbose'" != "")
	mata: fsort_inner("`varlist'", "`_sortindex'", `verbose')
end


mata:
void fsort_inner(string scalar vars, string scalar sortindex, real scalar verbose)
{
	class Factor scalar F
	F = factor(vars, "", verbose, "", ., ., ., 0)
	if (!F.is_sorted) {
		F.panelsetup()
		st_store(., sortindex, invorder(F.p))
	}
}
end


findfile "ftools.mata"
include "`r(fn)'"
exit
